/* ex: set tabstop=4 shiftwidth=4 expandtab: */
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <openssl/aes.h>
#include <openssl/MD5.h>

#include "nonce.h"


static inline void
xor_128(u_char *a, u_char *b, u_char *out)
{
	int i;

	for (i = 0; i < 16; i++)
		out[i] = a[i] ^ b[i];
}

void
aes_cbc_encrypt(AES_KEY *key, u_char *src, u_char *dst, int size)
{
	int i;
	u_char block[16];

	for (i = 0; i < size; i += 16) {
		memcpy(dst, src, 16);
		if (i)
			xor_128(dst, block, dst);
		AES_encrypt(dst, block, key);
		memcpy(dst, block, 16);

		dst += 16;
		src += 16;
	}
}

void
aes_cbc_decrypt(AES_KEY *key, u_char *src, u_char *dst, int size)
{
	int i;
	u_char block[16];
	u_char block_prev[16];

	memcpy(block, src, 16);
	memcpy(block_prev, src, 16);
	AES_decrypt(src, dst, key);

	dst += 16;
	src += 16;

	for (i = 16; i < size; i += 16) {
		memcpy(block, src, 16);
		memcpy(dst, src, 16);
		AES_decrypt(dst, dst, key);
		xor_128(dst, block_prev, dst);
		memcpy(block_prev, block, 16);

		dst += 16;
		src += 16;
	}
}

#if 0
static u_int g_userkey[] = {
	0x68109ADA,
	0x351FF0C3,
	0xE1E5D29A,
	0xACC98A8B
};
#endif

/* this is bound with nonce that we send in rtsp.c */
/* key = MD5(nonce + 3B8C7905473EB41C7392BA718F084439) */
#if 0
static u_int g_userkey[4] = {
	0x617B1DEB,
	0xDBD76772,
	0xFB43A703,
	0x6EB29482
};
#endif

static AES_KEY g_aes_enc_key;
static AES_KEY g_aes_dec_key;

void
crypto_init(void)
{
	u_int key[4] = { 0 };

#define MAGIC "3B8C7905473EB41C7392BA718F084439"
#define __nonce NONCE MAGIC

	MD5_CTX ctx;
	int i;

	MD5_Init(&ctx);
	MD5_Update(&ctx, __nonce, strlen(__nonce));
	MD5_Final((u_char *) key, &ctx);
	printf("AES key:\n");
	for (i = 0; i < 4; i++)
		printf("0x%08X\n", key[i]);
	printf("\n");

	AES_set_encrypt_key((const unsigned char *) key, 8 * sizeof(key), &g_aes_enc_key);
	AES_set_decrypt_key((const unsigned char *) key, 8 * sizeof(key), &g_aes_dec_key);
}

void
crypto_encrypt(unsigned char *src, unsigned char *dst, int size)
{
	aes_cbc_encrypt(&g_aes_enc_key, src, dst, size);
}

void
crypto_decrypt(unsigned char *src, unsigned char *dst, int size)
{
	aes_cbc_decrypt(&g_aes_dec_key, src, dst, size);
}

#ifdef TEST
int
main(void)
{
#if 0
	char buf[1024];
	char data[1024];

	memset(data, 0xD5, 1024);
	crypto_init();
	crypto_encrypt(data, buf, 1024);
	hexdump(buf, 1024);
	printf("----------------------\n");
	crypto_decrypt(buf, data, 1024);
	hexdump(data, 1024);
	return 0;

#else

	unsigned char rawData[] = {
		0xAE, 0x78, 0xD6, 0xAE, 0x54, 0x1B, 0xCD, 0xD5, 0x61, 0x73, 0xE0, 0x60,
		0x2A, 0x32, 0x0E, 0x40, 0xD7, 0x1C, 0x5C, 0x1A, 0xCD, 0x7E, 0xFF, 0xBA,
		0x59, 0xD7, 0x6E, 0x80, 0x6E, 0x7B, 0x55, 0x79, 0x32, 0x89, 0xE6, 0x5F,
		0xE6, 0x56, 0x3E, 0xB7, 0x39, 0xAF, 0x6F, 0x8F, 0x85, 0xDF, 0xCA, 0xAF,
		0x32, 0x89, 0xE6, 0x5F, 0xE6, 0x56, 0x3E, 0xB7, 0x39, 0xAF, 0x6F, 0x8F,
		0x85, 0xDF, 0xCA, 0xAF, 0x32, 0x89, 0xE6, 0x5F, 0xE6, 0x56, 0x3E, 0xB7,
		0x39, 0xAF, 0x6F, 0x8F, 0x85, 0xDF, 0xCA, 0xAF, 0x32, 0x89, 0xE6, 0x5F,
		0xE6, 0x56, 0x3E, 0xB7, 0x39, 0xAF, 0x6F, 0x8F, 0x85, 0xDF, 0xCA, 0xAF,
		0x32, 0x89, 0xE6, 0x5F, 0xE6, 0x56, 0x3E, 0xB7, 0x39, 0xAF, 0x6F, 0x8F,
		0x85, 0xDF, 0xCA, 0xAF, 0x32, 0x89, 0xE6, 0x5F, 0xE6, 0x56, 0x3E, 0xB7,
		0x39, 0xAF, 0x6F, 0x8F, 0x85, 0xDF, 0xCA, 0xAF
	};

	/*
	unsigned char rawData[128] = {
	0x02, 0x30, 0xB5, 0xB8, 0x29, 0xDF, 0x79, 0xA1, 0x09, 0x71, 0xFD, 0x60,
	0xF8, 0x8B, 0x24, 0xBC, 0xED, 0x0C, 0xE3, 0xC7, 0xC4, 0x34, 0x8C, 0x5F,
	0x5F, 0x9B, 0xD3, 0xEC, 0x14, 0x04, 0x2D, 0x2F, 0x14, 0x51, 0x77, 0x64,
	0x7F, 0x62, 0xA9, 0x62, 0x73, 0x26, 0x9D, 0xB2, 0x37, 0xC6, 0xFB, 0xD6,
	0x14, 0x51, 0x77, 0x64, 0x7F, 0x62, 0xA9, 0x62, 0x73, 0x26, 0x9D, 0xB2,
	0x37, 0xC6, 0xFB, 0xD6, 0x14, 0x51, 0x77, 0x64, 0x7F, 0x62, 0xA9, 0x62,
	0x73, 0x26, 0x9D, 0xB2, 0x37, 0xC6, 0xFB, 0xD6, 0x14, 0x51, 0x77, 0x64,
	0x7F, 0x62, 0xA9, 0x62, 0x73, 0x26, 0x9D, 0xB2, 0x37, 0xC6, 0xFB, 0xD6,
	0x14, 0x51, 0x77, 0x64, 0x7F, 0x62, 0xA9, 0x62, 0x73, 0x26, 0x9D, 0xB2,
	0x37, 0xC6, 0xFB, 0xD6, 0x14, 0x51, 0x77, 0x64, 0x7F, 0x62, 0xA9, 0x62,
	0x73, 0x26, 0x9D, 0xB2, 0x37, 0xC6, 0xFB, 0xD6
};
	*/
	char buf[sizeof(rawData)] = {0};

	crypto_init();
	crypto_decrypt(rawData, buf, sizeof(rawData));
	hexdump(buf, sizeof(rawData));
	printf("-----------------\n");
	crypto_encrypt(buf, rawData, sizeof(rawData));
	hexdump(rawData, sizeof(rawData));

#endif
	return 0;
}
#endif
